package mwa.cs.hh.biz;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import mwa.cs.dao.AllowanceDAO;
import mwa.cs.dao.CustMonthlyDAO;
import mwa.cs.dao.VatRateDAO;
import mwa.cs.dao.WaterChargeDAO;
import mwa.cs.database.Database;
import mwa.cs.util.JDate;

/**
 * Class for supporting all function in meter system
 */
public class MeterFunction {
	
	/**
	 * calculate consumption per day
	 * @param pnConsumptions 3 recent consumption
	 * @param pnDaysInMonth 3 recent days in months
	 * @return consumption per day
	 */
	public static String calConsumptionPerDay(double[] pnConsumptions, double[] pnDaysInMonth) {
		// set 0 to 1 for saving NaN occur ( ?/0 i.e. 5/0, 10/0, 3/0)
		if (pnDaysInMonth[0] == 0) pnDaysInMonth[0] = 1;
		if (pnDaysInMonth[1] == 0) pnDaysInMonth[1] = 1;
		if (pnDaysInMonth[2] == 0) pnDaysInMonth[2] = 1;
		double[] pnConsumptionPerDays = { pnConsumptions[0] / pnDaysInMonth[0], 
				pnConsumptions[1] / pnDaysInMonth[1], pnConsumptions[2] / pnDaysInMonth[2] };
		// finding max, mid, min value from attributes
		double pnMax = 0, pnMid = 0, pnMin = 0;
		pnMax = maxValue(pnConsumptionPerDays);
		pnMid = midValue(pnConsumptionPerDays);
		pnMin = minValue(pnConsumptionPerDays);
		// check condition
		if (pnMin > 0 && pnMid > 0 && pnMax > 0) {
			if ((pnMax > (pnMid * 1.5)) && (pnMid > (pnMin * 1.5)))
				return String.format( "%.2f", pnMid );
			else if ((pnMax > (pnMid * 1.5)) && (pnMid <= (pnMin * 1.5)))
				return String.format( "%.2f", ((pnMid + pnMin) / 2) );
			else if ((pnMax <= (pnMid * 1.5)) && (pnMid > (pnMin * 1.5)))
				return String.format( "%.2f", ((pnMax + pnMid) / 2) );
			else
				return String.format( "%.2f", ((pnMax + pnMid + pnMin) / 3) );
		} else if (pnMin == 0 && pnMid > 0 && pnMax > 0)
			return String.format( "%.2f", ((pnMax + pnMid) / 2) );
		else if (pnMin == 0 && pnMid == 0 & pnMax > 0)
			return String.format( "%.2f", pnMax );
		else
			return String.format( "%.2f", pnMax );
	}

	/**
	 * finding max value
	 * @param pnValues arrays of number
	 * @return max value
	 */
	public static double maxValue(double[] pnValues) {
		double pnMaxValue = pnValues[0];
		for (int i = 0; i < pnValues.length; i++) {
			if (pnValues[i] > pnMaxValue) {
				pnMaxValue = pnValues[i];
			}
		}
		return pnMaxValue;
	}
	
	/**
	 * finding min value
	 * @param pnValues arrays of number
	 * @return min value
	 */
	public static double minValue(double[] pnValues) {
		double pnMinValue = pnValues[0];
		for (int i = 0; i < pnValues.length; i++) {
			if (pnValues[i] < pnMinValue) {
				pnMinValue = pnValues[i];
			}
		}
		return pnMinValue;
	}
	
	/**
	 * finding mid value
	 * @param pnValues arrays of 3 number
	 * @return mid value
	 */
	public static double midValue(double[] pnValues) {
		if (pnValues[0] > pnValues[1]) {
			if (pnValues[1] > pnValues[2]) {
				return pnValues[1];
			} else if (pnValues[0] > pnValues[2]) {
				return pnValues[2];
			} else {
				return pnValues[0];
			}
		} else {
			if (pnValues[0] > pnValues[2]) {
				return pnValues[0];
			} else if (pnValues[1] > pnValues[2]) {
				return pnValues[2];
			} else {
				return pnValues[1];
			}
		}		
	}
	
	// คิดค่าน้ำ รับหน่วยที่ใช้ ออกมาเป็น ค่าน้ำ
	public static String calNormalUsedUnitWater(int pnSiteId, String paCustomerClass,double pnUsedUnit){
		double vnTotal = 0.00;
		double vnWaterRate = 0.0;
		double vnWaterBaseComption = 0.0;
		double vnWaterBaseCharge = 0.0;
		DecimalFormat formatter = new DecimalFormat("#,##0.00");
		Database db = new Database();
		WaterChargeDAO voWaterChrageManage = new WaterChargeDAO(db);
		List<Map<String, Object>> voWaterChargeResult = voWaterChrageManage.findCalPrepareData(pnSiteId, paCustomerClass);
		Map<String, Object> voMinWateraseConsumption = voWaterChrageManage.findMinWaterBaseConsumption(pnSiteId, paCustomerClass);
		double vnMinWaterBaseConsumption = (Double.parseDouble(( voMinWateraseConsumption.get("WATER_BASE_CONSUMPTION")).toString()));
		double vnMaxWaterUsedEnd = Double.parseDouble(voWaterChargeResult.get(voWaterChargeResult.size()-1).get("WATER_USED_END").toString());
		if( pnUsedUnit > vnMaxWaterUsedEnd){
			for( int n = 0; n < 1; n++ ){
				Map<String, Object> voObject2 = voWaterChargeResult.get(voWaterChargeResult.size()-1);
				vnWaterRate = (Double.parseDouble(( voObject2.get("WATER_RATE")).toString()));
				vnWaterBaseComption = (Double.parseDouble(( voObject2.get("WATER_BASE_CONSUMPTION")).toString()));
				vnWaterBaseCharge = (Double.parseDouble(( voObject2.get("WATER_BASE_CHARGE")).toString()));
				vnTotal = ((pnUsedUnit - vnWaterBaseComption) * vnWaterRate ) + vnWaterBaseCharge;
			}
		} else if ( pnUsedUnit >= 0 ){
			for (int i = 0; i < voWaterChargeResult.size(); i++){
				Map<String, Object> voObject = voWaterChargeResult.get(i);
				int vnWaterUsedStart = (Integer.parseInt(((BigDecimal) voObject.get("WATER_USED_START")).toString()));
				int vnWaterUsedEnd = (Integer.parseInt(((BigDecimal) voObject.get("WATER_USED_END")).toString()));
				if ( pnUsedUnit > vnMinWaterBaseConsumption){
					if ( pnUsedUnit >= vnWaterUsedStart && pnUsedUnit <= vnWaterUsedEnd){
						vnWaterRate = (Double.parseDouble(( voObject.get("WATER_RATE")).toString()));
						vnWaterBaseComption = (Double.parseDouble(( voObject.get("WATER_BASE_CONSUMPTION")).toString()));
						vnWaterBaseCharge = (Double.parseDouble(( voObject.get("WATER_BASE_CHARGE")).toString()));
						vnTotal = ((pnUsedUnit - vnWaterBaseComption) * vnWaterRate ) + vnWaterBaseCharge;
					}
				} else {
					vnTotal = vnWaterBaseCharge = (Double.parseDouble(( voObject.get("WATER_BASE_CHARGE")).toString()));
					break;
				}
			}
		}
		db.close();
		//System.out.println("สรุปค่าน้ำ :"+formatter.format(vnTotal));
		//return String.valueOf(vnTotal);
		return formatter.format(vnTotal);
	}	
	
	// คำนวณจำนวนวันระหว่าง Date
	public static String CalDurationBetweenTwoDates(String readLastDate, String readCurrentDate) throws ParseException {
		String vaDayOfBetweenTwoDates = "";
		SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); 
		Date d1 = format.parse(readLastDate);
		Date d2 = format.parse(readCurrentDate);
		long diff = d2.getTime() - d1.getTime();
		long diffDay = diff / (24 * 60 * 60 * 1000);
		vaDayOfBetweenTwoDates = String.valueOf(diffDay);
		return vaDayOfBetweenTwoDates;
	}
	
	// คำนวณน้ำใช้เฉลี่ยต่อวัน 3 เดือนย้อนหลัง
	public static String calculateAverageConsumption(int pnSiteId, String paAccount) {
		double[] vnConsumption = new double[3];
		double[] vnDays = new double[3];
		Database db = new Database();		
		CustMonthlyDAO voCustMonthlyManagement = new CustMonthlyDAO(db);
		String vaMaxMonth = voCustMonthlyManagement.findMaxMonth(pnSiteId);
		List<Map<String, Object>> result = voCustMonthlyManagement.findMaxYearData(pnSiteId, paAccount, vaMaxMonth);
		if (result == null) {
			// do nothing
		} else if (result.size() > 2) { // กรณีไม่ข้ามปี
			for (int i = 0; i < 3; i++) {
				Map<String, Object> voCustMonthlyObjects = result.get(i);
				String vaYear = voCustMonthlyObjects.get("PERIOD_YEAR").toString();
				String vaMonth  = voCustMonthlyObjects.get("PERIOD_MONTH").toString();
				String vaConsumption = voCustMonthlyObjects.get("CONSUMPTION").toString();
				vnDays[i] = Double.parseDouble(JDate.getEndMonthDate(vaYear, vaMonth));
				vnConsumption[i] = Double.parseDouble(vaConsumption);
			}
		} else if (result.size() == 2){ // กรณีอยู่ในปี 2 เดือน, ปีก่อนหน้า 1 เดือน
			// ข้อมูลปีล่าสุด 2 เดือน
			for (int i = 0; i < 2; i++) {
				Map<String, Object> voCustMonthlyObjects = result.get(i);
				String vaYear = voCustMonthlyObjects.get("PERIOD_YEAR").toString();
				String vaMonth  = voCustMonthlyObjects.get("PERIOD_MONTH").toString();
				String vaConsumption = voCustMonthlyObjects.get("CONSUMPTION").toString();
				vnDays[i] = Double.parseDouble(JDate.getEndMonthDate(vaYear, vaMonth));
				vnConsumption[i] = Double.parseDouble(vaConsumption);
			}
			// ข้อมูลปีก่อนหน้า 1 เดือน
			List<Map<String, Object>> result2 =  voCustMonthlyManagement.findPreviousMaxYearData(pnSiteId, paAccount, vaMaxMonth);
			if (result2 != null) {	
				Map<String, Object> voCustMonthlyObjects = result2.get(0);
				String vaYear = voCustMonthlyObjects.get("PERIOD_YEAR").toString();
				String vaMonth  = voCustMonthlyObjects.get("PERIOD_MONTH").toString();
				String vaConsumption = voCustMonthlyObjects.get("CONSUMPTION").toString();
				vnDays[2] = Double.parseDouble(JDate.getEndMonthDate(vaYear, vaMonth));
				vnConsumption[2] = Double.parseDouble(vaConsumption);
			}
		} else if (result.size() == 1) { // กรณีอยู่ในปี 1 เดือน, ปีก่อนหน้า 2 เดือน
			// ข้อมูลปีล่าสุด 1 เดือน
			for (int i = 0; i < 1; i++) {
				Map<String, Object> voCustMonthlyObjects = result.get(i);
				String vaYear = voCustMonthlyObjects.get("PERIOD_YEAR").toString();
				String vaMonth  = voCustMonthlyObjects.get("PERIOD_MONTH").toString();
				String vaConsumption = voCustMonthlyObjects.get("CONSUMPTION").toString();
				vnDays[i] = Double.parseDouble(JDate.getEndMonthDate(vaYear, vaMonth));
				vnConsumption[i] = Double.parseDouble(vaConsumption);
			}
			// ข้อมูลปีก่อนหน้า 2 เดือน
			List<Map<String, Object>> result2 = voCustMonthlyManagement.findPreviousMaxYearData(pnSiteId, paAccount, vaMaxMonth);
			if (result2 != null && result2.size() >= 2) {
				for (int i = 0; i < 2; i++) {
					Map<String, Object> voCustMonthlyObjects = result2.get(i);
					String vaYear = voCustMonthlyObjects.get("PERIOD_YEAR").toString();
					String vaMonth  = voCustMonthlyObjects.get("PERIOD_MONTH").toString();
					String vaConsumption = voCustMonthlyObjects.get("CONSUMPTION").toString();
					vnDays[i + 1] = Double.parseDouble(JDate.getEndMonthDate(vaYear, vaMonth));
					vnConsumption[i + 1] = Double.parseDouble(vaConsumption);
				}
			} else if (result2 != null && result2.size() == 1) {
				Map<String, Object> voCustMonthlyObjects = result2.get(0);
				String vaYear = voCustMonthlyObjects.get("PERIOD_YEAR").toString();
				String vaMonth  = voCustMonthlyObjects.get("PERIOD_MONTH").toString();
				String vaConsumption = voCustMonthlyObjects.get("CONSUMPTION").toString();
				vnDays[1] = Double.parseDouble(JDate.getEndMonthDate(vaYear, vaMonth));
				vnConsumption[1] = Double.parseDouble(vaConsumption);
			}
		}
		db.close();
		return calConsumptionPerDay(vnConsumption, vnDays);
	}
	
	// คำนวณภาษี เมื่อมีการแก้ไข ค่าน้ำ
	public static String calVatRate(int siteId, String currentDate, String waterCharge, String waterFee){
		double vatAmount = 0.00;
		String vatRate = "";
		DecimalFormat formatter = new DecimalFormat("#,##0.00");
		Database db = new Database();
		VatRateDAO voVatRateDAO = new VatRateDAO(db);
		Map<String, Object> voMap = new HashMap<String, Object>();
		voMap = voVatRateDAO.getVatRate(siteId, currentDate);
		vatRate = ""+ voMap.get("RATE");
		double waterChargeCal = Double.parseDouble(waterCharge.replace(",", ""));
		double waterFeeCal = Double.parseDouble(waterFee.replace(",", ""));
		
		vatAmount = ((waterChargeCal + waterFeeCal) * Double.parseDouble(vatRate.toString()));
		return formatter.format(vatAmount);
	}
	
	// ส่วนลดทหารผ่านศึก
	public static String[] getDiscountAllowance(int siteId){
		String discount = "";
		String type = "";
		Database db = new Database();
		AllowanceDAO voAllowanceDAO = new AllowanceDAO(db);
		Map<String, Object> voMap = new HashMap<String, Object>();
		voMap = voAllowanceDAO.getAllowance(siteId);
		type = ""+ voMap.get("TYPE");
		discount = ""+ voMap.get("DISCOUNT");
		String [] data = {type,discount};
		
		return data;
	}
}
